#include <Arduino.h>
/*
  提示：
  ws2812 8*32软屏
  开发板选择 NodeMCU 1.0 D1 mini

*/
#include <FastLED.h>
#include "OneButton.h"
//#include <Adafruit_NeoPixel.h>
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include "GitFans.h"
#include <DHT.h>//包含DHT头文件
#include <arduinoFFT.h>
#define SAMPLES 64        // Must be a power of 2
#define MIC_IN A0         // Use D0 for mic input
#define NUM_LEDS    256    // 灯珠数
#define xres 32            // Total number of  columns in the display
#define yres 8            // Total number of  rows in the display
#define BRIGHTNESS  150    // LED 亮度 
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB 

double vReal[SAMPLES];
double vImag[SAMPLES];

#define DHTPIN 2      //定义DHT11模块连接管脚io2 （D4）
#define DHTTYPE DHT11   // 使用温度湿度模块的类型为DHT11

#define LED_PIN              4   // D2 ws2812 DAT 接的引脚编号
#define buttonPin   15       //D8 ttp223
//#define colorButtonPin   16    //D0 未使用
#define NUMPIXELS      256                       //ws2812 灯数
int   maxBrightness = 250;
#include <NTPClient.h>

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(xres, yres, 1, 1, LED_PIN,
                            NEO_MATRIX_TOP  + NEO_TILE_LEFT  + NEO_MATRIX_COLUMNS   + NEO_MATRIX_PROGRESSIVE +
                            NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG,
                            NEO_GRB + NEO_KHZ800);

int x = matrix.width();
int pass = 0;
int Mode = 0;
int color_index = 0;
String  H;
String  M;
String  S;//秒
int D;//星期几 0为周日
String timeText = "Time";
String UID = "4772302";    //bilibili UID
DHT dht(DHTPIN, DHTTYPE);  //定义dht
float humi_read = 0, temp_read = 0; //定义浮点型全局变量 储存传感器读取的温湿度数据
int freq_gain2[xres] = {40, 42, 45, 47, 51, 55, 57, 59, 62, 65, 69, 71, 73, 76, 80, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 60, 56, 52, 50, 46, 54, 40};
//算出来的长度值

int Intensity[xres] = { }; // initialize Frequency Intensity to zero
int Displacement = 1;
//CRGB leds[NUM_LEDS];            // Create LED Object
arduinoFFT FFT = arduinoFFT();  // Create FFT object

//RGB颜色数组https://www.sojson.com/rgb.html
uint16_t myRGBColorPalette[14] = { matrix.Color(30,144,255), matrix.Color(135,206,250), matrix.Color(0, 0, 205),  matrix.Color(150, 0, 150),
                                     matrix.Color(255,255,255),  matrix.Color(255,240,245),  matrix.Color(255,193,193),matrix.Color(255,106,106), 
                                     matrix.Color(255,165,0),  matrix.Color(255,64,64),  matrix.Color(255,255,0),  matrix.Color( 46,139,87),
                                   matrix.Color(255,0,255),  matrix.Color(0,250,154)
                                 };

String FansURL;
GitFans gitfans;
bool colon = true;

String bitdata20[10]={
  "111101101101111","010110010010111",
  "111001111100111","111001111001111",
  "101101111001001","111100111001111",
  "111100111101111","111001001001001",
  "111101111101111","111101111001111"
};

WiFiUDP udp;
NTPClient timeClient(udp, "ntp1.aliyun.com", 60 * 60 * 8, 30 * 60 * 1000);
OneButton button(buttonPin, false, false);
unsigned long lastTime;

void modeChange()
{
  matrix.clear();
  matrix.show();
  if (++Mode > 4)Mode = 0;//模式变化
  Serial.println("按键切换模式");
  Serial.println(Mode);
  switchMode(true);
}

void colorChange(){
  if (++color_index > 13)color_index = 0;//模式变化
  Serial.println("按键切换颜色");
  Serial.println(color_index);
  switchMode(true);
}

void setup() {
  Serial.begin(115200);
  WiFiManager wifiManager;
  wifiManager.autoConnect("MatrixTime");
  // 如果您希望该WiFi添加密码，可以使用以下语句：
  // wifiManager.autoConnect("AutoConnectAP", "12345678");
  // 以上语句中的12345678是连接AutoConnectAP的密码

  // WiFi连接成功后将通过串口监视器输出连接成功信息
  Serial.println("");
  Serial.print("ESP8266 Connected to ");
  Serial.println(WiFi.SSID());              // WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // IP
  button.attachClick(colorChange);
  button.attachDoubleClick(modeChange);
  pinMode(MIC_IN, INPUT);
  //FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  matrix.begin();

  matrix.setTextWrap(false);
  matrix.setBrightness(70);
  //matrix.setTextColor(colors[0]);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.print("Connected! IP address: ");
  Serial.println(WiFi.localIP());

  FansURL = gitfans.GitURL(UID);    //获得API
}

//RGB颜色-> https://www.sojson.com/rgb.html

//时钟图案
void ClockPattern(){
  String  pstr = "0011111001001001010010010100111101000001010000010011111000000000";
  for (int i = 0; i < 8; i = i + (1)) {
    for(int j = 0; j < 8; j = j + (1)){
      if (String(pstr.charAt((j*8+i))).toInt() != 0) {
        matrix.drawPixel(i,j,matrix.Color(232,232,232));
      } else {
        matrix.drawPixel(i,j,matrix.Color(0, 0, 0));
      }
    }
  } 
}

//B站图案
void BPattern(){
  String  pstr = "00100010000101000011111001000001010101010100000100111110";
  for (int i = 0; i < 8; i = i + (1)) {
    for(int j = 0; j < 8; j = j + (1)){
      if (String(pstr.charAt((j*8+i))).toInt() != 0) {
        matrix.drawPixel(i,j,matrix.Color(0,191,255));
      } else {
        matrix.drawPixel(i,j,matrix.Color(0, 0, 0));
      }
    }
  } 
}

//温度计图案
void TempPattern(){
  // white matrix.Color(255,255,255)
  // red matrix.Color(255,48,48)
  drawFastYLine(1,4,3,matrix.Color(255,255,255));
  drawFastYLine(2,0,5,matrix.Color(255,255,255));
  drawFastYLine(3,0,1,matrix.Color(255,255,255));
  drawFastYLine(4,0,5,matrix.Color(255,255,255));
  drawFastYLine(2,5,2,matrix.Color(255,48,48));
  drawFastYLine(3,2,5,matrix.Color(255,48,48));
  drawFastYLine(4,5,2,matrix.Color(255,48,48));
  drawFastXLine(2,7,3,matrix.Color(255,255,255));
  drawFastYLine(5,4,3,matrix.Color(255,255,255));  
}

void cdPattern(int16_t x, int16_t y, uint16_t color){
  matrix.drawPixel(x+2,y+2,color);
  drawFastYLine(x+4,y+3,y+3,color);
  matrix.drawPixel(x+5,y+2,color);
  matrix.drawPixel(x+6,y+2,color);
  matrix.drawPixel(x+5,y+6,color);
  matrix.drawPixel(x+6,y+6,color);
}
//百分符号
void pcPattern(int16_t x, int16_t y, uint16_t color){
  matrix.drawPixel(x+3,y+2,color);
  matrix.drawPixel(x+2,y+6,color);
  matrix.drawPixel(x+3,y+5,color);
  matrix.drawPixel(x+4,y+4,color);
  matrix.drawPixel(x+5,y+3,color);
  matrix.drawPixel(x+6,y+2,color);
  matrix.drawPixel(x+5,y+6,color);

}

void drawFastYLine(int16_t x, int16_t y, int16_t h, uint16_t color){
  for(int i=y;i<y+h;i++){
    matrix.drawPixel(x,i,color);
  }
}

void drawFastXLine(int16_t x, int16_t y, int16_t h, uint16_t color){
  for(int i=x;i<x+h;i++){
    matrix.drawPixel(i,y,color);
  }
}


void showColon(int x,int y,bool l,uint16_t colorxy){
  String pstr = "101";
  for(int j = y; j < y+3; j = j + (1)){
    if (String(pstr.charAt(j-y)).toInt() != 0) {
      if(l){
        matrix.drawPixel(x,j,colorxy);
      }else{
        matrix.drawPixel(x,j,matrix.Color(0, 0, 0));
      }
    } else {
      matrix.drawPixel(x,j,matrix.Color(0, 0, 0));
    }
  }
}

void showTime()
{
  timeClient.update();
  H = timeClient.getFormattedTime().substring(0, 2);
  M = timeClient.getFormattedTime().substring(3, 5);
  timeText = H + ":" + M;
  ClockPattern();
  if ( millis() - lastTime > 1000)
  {
    lastTime = millis(); 
    showbitnumber(H,3,5,11,1,matrix.Color(30,144,255));
    showbitnumber(M,3,5,21,1,matrix.Color(30,144,255));
    if(colon){
      colon = false;  
    }else{
      colon = true;  
    }
    showColon(19,2,colon,matrix.Color(30,144,255));
    matrix.show();
  }
}

void showTime3(bool implement)
{
  timeClient.update();
  H = timeClient.getFormattedTime().substring(0, 2);
  M = timeClient.getFormattedTime().substring(3, 5);
  S = timeClient.getFormattedTime().substring(6, 8);
  D = timeClient.getDay();
  timeText = H + ":" + M;
  if ( millis() - lastTime > 1000 | implement)
  {
    if(!implement){
      lastTime = millis(); 
    }
    showbitnumber(H,3,5,2,1,myRGBColorPalette[color_index]);
    showbitnumber(M,3,5,12,1,myRGBColorPalette[color_index]);
    showbitnumber(S,3,5,22,1,myRGBColorPalette[color_index]);
    //冒号
    showColon(10,2,true,myRGBColorPalette[color_index]);
    showColon(20,2,true,myRGBColorPalette[color_index]);
    //星期
    showWeek(2,7,myRGBColorPalette[color_index]);
    showWeekDay(2,7,matrix.Color(138,43,226));
    matrix.show();
  }
}

void showWeek(int x, int y, uint16_t colorxy) {
  for(int i=0;i<7;i++){
    drawFastXLine(x+i*4,y,3,colorxy);
  }
}

void showWeekDay(int x, int y, uint16_t colorxy) {
  int d = D;
  if(D == 0){
    d = 7;
  }
  drawFastXLine(x+(d-1)*4,y,3,colorxy);
}

void showbitmap(String bitrgbstr, int xlength, int ylength, int x, int y, uint16_t colorxy) {
  //Serial.println("bitrgbstr = " + bitrgbstr);
  for (int i = x; i < x+(xlength); i = i + (1)) {
    for(int j = y; j < y+(ylength); j = j + (1)){
      if (String(bitrgbstr.charAt(((j-y)*xlength+i-x))).toInt() != 0) {
        matrix.drawPixel(i,j,colorxy);
      } else {
        matrix.drawPixel(i,j,matrix.Color( 0, 0, 0));
      }
    }
  }
}


void showbitnumber(String number, int xlength, int ylength, int x, int y, uint16_t colorxy){
  if(number.toInt()<10){
    showbitmap(bitdata20[(int)(0)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
  }else if(number.toInt()<100){
    showbitmap(bitdata20[(int)((String(number.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
  }else if(number.toInt()<1000){
    showbitmap(bitdata20[(int)((String(number.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
  }else if(number.toInt()<10000){
    showbitmap(bitdata20[(int)((String(number.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(3)).toInt() + 1) - 1)],xlength,ylength, x+12, y, colorxy);
  }else if(number.toInt()<100000){
    showbitmap(bitdata20[(int)((String(number.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(3)).toInt() + 1) - 1)],xlength,ylength, x+12, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(4)).toInt() + 1) - 1)],xlength,ylength, x+16, y, colorxy);
  }else if(number.toInt()<1000000){
    showbitmap(bitdata20[(int)((String(number.charAt(0)).toInt() + 1) - 1)],xlength,ylength, x, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(1)).toInt() + 1) - 1)],xlength,ylength, x+4, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(2)).toInt() + 1) - 1)],xlength,ylength, x+8, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(3)).toInt() + 1) - 1)],xlength,ylength, x+12, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(4)).toInt() + 1) - 1)],xlength,ylength, x+16, y, colorxy);
    showbitmap(bitdata20[(int)((String(number.charAt(5)).toInt() + 1) - 1)],xlength,ylength, x+20, y, colorxy);
  }
}

void showFs(bool implement){
  BPattern();
  if ( millis() - lastTime > 20000 | implement)
  {
    lastTime = millis();
    
    gitfans.ParseFans(FansURL);    //处理粉丝数据
    Serial.println(Fansnumber);    //打印粉丝数
    if(Fansnumber<100){
      //showbitnumber(String(Fansnumber),4,8,0,0,pad.Color(0,178,34,34));
      showbitnumber(String(Fansnumber),3,5,25,2,matrix.Color(178,34,34));
    }else if (Fansnumber<1000){
      showbitnumber(String(Fansnumber),3,5,21,2,matrix.Color(178,34,34));
    }else if (Fansnumber<10000){
      showbitnumber(String(Fansnumber),3,5,17,2,matrix.Color(178,34,34));
    }else if (Fansnumber<100000){
      showbitnumber(String(Fansnumber),3,5,13,2,matrix.Color(178,34,34));
    }else if (Fansnumber<1000000){
      showbitnumber(String(Fansnumber),3,5,9,2,matrix.Color(178,34,34));
    }
    matrix.show();
  }
}

void dhtRead(){
  float h = dht.readHumidity(true);//读取DHT11传感器的湿度 并赋值给h
  float t = dht.readTemperature(true);//读取传感器的温度   并赋值给t
  
  if (isnan(h) || isnan(t))//判断是否成功读取到温湿度数据
  {
      Serial.println("Failed to read from DHT sensor!");//读取温湿度失败！
  }
  else
  {
      t = dht.convertFtoC(t);//将华氏度转换为摄氏度
      Serial.println("Humidity: "+ String(h)+ " %");
      Serial.println("Temperature: "+ String(t)+ " *C");
      humi_read = h;//将读取到的湿度赋值给全局变量humi_read
      temp_read = t;//将读取到的温度赋值给全局变量temp_read
  }
}

void showTemp(bool implement){
  if ( millis() - lastTime > 20000 | implement)
  {
    lastTime = millis();
    dhtRead();
    TempPattern();
    showbitnumber(String((int)temp_read),3,5,13,2,matrix.Color(147,112,219));
    cdPattern(23,0,matrix.Color(147,112,219));
    matrix.show();
  }
}

void showHumi(bool implement){
  if ( millis() - lastTime > 20000 | implement)
  {
    lastTime = millis();
    dhtRead();
    TempPattern();
    showbitnumber(String((int)humi_read),3,5,13,2,matrix.Color(147,112,219));
    pcPattern(23,0,matrix.Color(147,112,219));
    matrix.show();
  }
}

void showFFT(){

    //Collect Samples
    getSamples();
    //Update Display
    displayUpdate();
    matrix.show();
    delay(1);
    
}

void getSamples(){
  for(int i = 0; i < SAMPLES; i++){
    vReal[i] = analogRead(MIC_IN);
    Serial.println(vReal[i]);
    vImag[i] = 0;
  }
  //FFT
  FFT.Windowing(vReal, 1, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  //Update Intensity Array
  for(int i = 2; i < (xres*Displacement)+2; i+=Displacement){
    vReal[i] = constrain(vReal[i],freq_gain2[i-2] ,1300);            // set max value for input data
    vReal[i] = map(vReal[i], freq_gain2[i-2], 1300, 0, yres);        // map data to fit our display
    Intensity[(i/Displacement)-2] --;                      // Decrease displayed value
    if (vReal[i] > Intensity[(i/Displacement)-2])          // Match displayed value to measured value
      Intensity[(i/Displacement)-2] = vReal[i];
  }
}


void displayUpdate(){
  int color = 0;
  for(int i = 0; i < xres; i++){
    CRGB c_color = CHSV(color, 255, 255);
    if(color_index>0){
      drawFastYLine(i,8-Intensity[i],Intensity[i],myRGBColorPalette[color_index]);
    }else{
      drawFastYLine(i,8-Intensity[i],Intensity[i],matrix.Color(c_color.r,c_color.g,c_color.b));
    }  
    drawFastYLine(i,0,7-Intensity[i],matrix.Color(0,0,0));

    color += 255/xres;             // Increment the Hue to get the Rainbow
    if(color>255){
      color = 0;
    }
  } 
}

void switchMode(bool change){
  switch (Mode)
  {
    case 0:
      showTime3(change);
      break;
    case 1:
      showFs(change);
      break;
    case 2:
      showTemp(change);
      break;
    case 3:
      showHumi(change);
      break;
    case 4:
      showFFT();
      break;
  }
}

void loop()
{
  button.tick();
  switchMode(false);
}